﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MapViewer.Loaders
{
	class UrlLoader : ILoader
	{
		private static readonly System.Text.RegularExpressions.Regex mapFile = new System.Text.RegularExpressions.Regex("\"([^\"]*map_\\d+\\.dat)\"", System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
		#region ILoader Members

		public void Load(Action<NamedBinaryTag.TagFile> callback, Model.RecentItem source)
		{
			NamedBinaryTag.TagFile backFile = new NamedBinaryTag.TagFile();
			string url = (source as Model.UrlRecentItem).Url;
			System.Net.WebClient client = new System.Net.WebClient();
			client.OpenReadCompleted += delegate(object sender, System.Net.OpenReadCompletedEventArgs args)
			{
				using (System.IO.Stream stream = args.Result)
				{
					if (System.Text.RegularExpressions.Regex.IsMatch(client.ResponseHeaders["Content-Type"], @"^text/html\s*(;\s*charset\s*=)?"))
					{
						LoadCombinedFile(callback, stream, new Uri(url));
					}
					else
					{
						backFile.Load(stream);
						callback(backFile);
					}
				}
			};
			client.OpenReadAsync(new Uri(url));
		}

		#endregion

		private void LoadCombinedFile(Action<NamedBinaryTag.TagFile> callback, System.IO.Stream folderStream, Uri baseUri)
		{
#if SILVERLIGHT
			CombineSourceBuilder builder = new CombineSourceBuilder();
			string content = GetContent(folderStream);
			System.Text.RegularExpressions.Match match = mapFile.Match(content);
			System.Net.WebClient client = new System.Net.WebClient();
			IList<System.IO.Stream> fileSources = new List<System.IO.Stream>();
			byte[] buffer = new byte[10480];
			int read = 0;
			Action fileDone = delegate
			{
				if (match.Success)
				{
					Uri fileUri = new Uri(baseUri, match.Groups[1].Value);
					client.OpenReadAsync(fileUri);
				}
				else
				{
					IList<NamedBinaryTag.TagFile> dataFiles = builder.LoadFiles(fileSources.GetEnumerator());
					FinalizeCombineFile(callback, builder, dataFiles);
				}
			};
			client.OpenReadCompleted += delegate(object sender, System.Net.OpenReadCompletedEventArgs args)
			{
				System.IO.Stream memory = new System.IO.MemoryStream(10480);
				System.IO.Stream stream = args.Result;
				while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
				{
					memory.Write(buffer, 0, read);
				}
				memory.Seek(0, System.IO.SeekOrigin.Begin);
				fileSources.Add(memory);
				match = match.NextMatch();
				fileDone();
			};
			fileDone();
#else
			CombineSourceBuilder builder = new CombineSourceBuilder();
			IList<NamedBinaryTag.TagFile> dataFiles = builder.LoadFiles(GetFileEnumerator(folderStream, baseUri));
			FinalizeCombineFile(callback, builder, dataFiles);
#endif
		}

		private void FinalizeCombineFile(Action<NamedBinaryTag.TagFile> callback, CombineSourceBuilder builder, IList<NamedBinaryTag.TagFile> dataFiles)
		{
			NamedBinaryTag.TagFile backFile = new NamedBinaryTag.TagFile();
			System.Windows.Rect bounds = builder.ComputeBounds(dataFiles.ToArray());
			byte[] image = builder.CreateImage(dataFiles.ToArray(), bounds);
			backFile.Init();
			backFile.RootTag.Items.Add(builder.MakeDataTag(dataFiles, image, bounds));
			callback(backFile);
		}

#if !SILVERLIGHT
		private IEnumerator<System.IO.Stream> GetFileEnumerator(System.IO.Stream sourceStream, Uri baseUri)
		{
			string content = GetContent(sourceStream);
			System.Text.RegularExpressions.Match match = mapFile.Match(content);
			while (match.Success)
			{
				Uri fileUri = new Uri(baseUri, match.Groups[1].Value);
				System.Net.WebClient client = new System.Net.WebClient();
				yield return client.OpenRead(fileUri);
				match = match.NextMatch();
			}
		}
#endif

		private string GetContent(System.IO.Stream sourceStream)
		{
			string content = string.Empty;
			using (System.IO.TextReader reader = new System.IO.StreamReader(sourceStream, Encoding.UTF8))
			{
				content = reader.ReadToEnd();
			}
			return content;
		}
	}
}
